//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Reflection;

namespace OpenLS.Chart.UI.Internals
{
    public class ScatterChartObserver: INotifyPropertyChanged
    {
        public ScatterChartObserver(ObservableCollection<ScatterSeries> series)
        {
            this.series = series;
            foreach (ScatterSeries s in series)
                RegiesterSeries(s);
            series.CollectionChanged += series_CollectionChanged;
        }

        private double? _xMinimum;

        public double? XMinimum
        {
            get
            {
                if (_xMinimum == null)
                    calculateMinMax();
                return _xMinimum;
            }
            private set { _xMinimum = value; notifyPropertyChanged("XMinimum"); }
        }
        private double? _yMinimum;

        public double? YMinimum
        {
            get
            {
                if (_yMinimum == null)
                    calculateMinMax();
                return _yMinimum;
            }
            set
            {
                if (_yMinimum == value)
                    return;
                _yMinimum = value; notifyPropertyChanged("YMinimum"); }
        }
        private double? _xMaximum;

        public double? XMaximum
        {
            get {
                if (_xMaximum == null)
                    calculateMinMax();
                return _xMaximum;
            }
            set { _xMaximum = value; notifyPropertyChanged("XMaximum"); }
        }
        private double? _yMaximum;

        public double? YMaximum
        {
            get {
                if (_yMaximum == null)
                    calculateMinMax();
                return _yMaximum;
            }
            set { if (_yMaximum == value)
                return;
                _yMaximum = value; notifyPropertyChanged("YMaximum");
            }
        }

        void calculateMinMax()
        {
            double xMin = double.MaxValue;
            double yMin = double.MaxValue;
            double xMax = double.MinValue;
            double yMax = double.MinValue;
            foreach (ScatterSeries ser in series)
            {
                if (ser.XValues is NumericDataSource)
                foreach (NumericValue v in ((NumericDataSource)ser.XValues).NumericValues)
                {
                    xMin = Math.Min(xMin, v.Value);
                    xMax = Math.Max(xMax, v.Value);
                }
                else
                {
                    xMin = 1;
                    xMax = Enumerable.Count(ser.XValues.Values);
                }
                foreach (NumericValue v in ser.YValues.NumericValues)
                {
                    yMin = Math.Min(yMin, v.Value);
                    yMax = Math.Max(yMax, v.Value);
                }
            }
            if (xMin != double.MaxValue || yMin != double.MaxValue)
            {
                XMaximum = xMax;
                XMinimum = xMin;
                YMaximum = yMax;
                YMinimum = yMin;

            }
        }
	
        void series_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
                foreach (ScatterSeries s in e.NewItems)
                {
                    RegiesterSeries(s);
                }
            if (e.OldItems != null)
                foreach (ScatterSeries s in e.OldItems)
                {
                    if (s.XValues is NumericDataSource)
                    ((NumericDataSource)s.XValues).ValueChanged -= OnValueChanged;
                    s.YValues.ValueChanged -= OnValueChanged;
                }
        }

        private void RegiesterSeries(ScatterSeries s)
        {
            if (s.XValues is NumericDataSource)
            ((NumericDataSource)s.XValues).ValueChanged += OnValueChanged;
            s.YValues.ValueChanged += OnValueChanged;
        }

        void OnValueChanged(object sender, EventArgs e)
        {
            Generation++;
            XMaximum = null;
            XMinimum = null;
            YMaximum = null;
            YMinimum = null;
        }

        readonly ObservableCollection<ScatterSeries> series;

        private int _generation;

        public int Generation
        {
            get { return _generation; }
            set
            {
                _generation = value;
                notifyPropertyChanged("Generation");
            }
        }
		

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        void notifyPropertyChanged(string propertyName)
        {
            Contract.Requires(GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null);
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
}